arduino之eeprom官方的读写read和get、write和put的用法和区别(详细介绍)

您所在的位置:网站首页 arduino 字符串操作 arduino之eeprom官方的读写read和get、write和put的用法和区别(详细介绍)

arduino之eeprom官方的读写read和get、write和put的用法和区别(详细介绍)

2024-07-12 00:53| 来源: 网络整理| 查看: 265

arduino eeprom的read和get、write和put的区别 介绍一、get和read的区别①read:一次读取一个字节②get:一次读取多个字节 二、put和write的区别①write:单字节写入②put:多个字节的写入 三、clear,crc,iteration,update的用法①clear:擦除所有②crc:可以用来校验写入数据的准确性③iteration:几种遍历的方法④update:与write相同的功能

介绍

在arduino的例子里面有关于eeprom的例子,里面主要有读和写的例子。其中读写都各有两个方法: 在这里插入图片描述 在这里简单介绍一下。

一、get和read的区别 ①read:一次读取一个字节

首先是read方法:read方法一次读取一个字节

#include // start reading from the first byte (address 0) of the EEPROM int address = 0; byte value; void setup() { // initialize serial and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } } void loop() { // read a byte from the current address of the EEPROM value = EEPROM.read(address); Serial.print(address); Serial.print("\t"); Serial.print(value, DEC); Serial.println(); address = address + 1; if (address == EEPROM.length()) { address = 0; } /*** As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an EEPROM address is also doable by a bitwise and of the length - 1. ++address &= EEPROM.length() - 1; ***/ delay(500); }

其实read方法就是

uint8_t read( int idx ) { return EERef( idx ); } ②get:一次读取多个字节

再是get方法:get方法可以一次读取多个字节,其实现也是比较厉害的(对于我这个程序小白而言)

#include void setup() { float f = 0.00f; //Variable to store data read from EEPROM. int eeAddress = 0; //EEPROM address to start reading from Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.print("Read float from EEPROM: "); //Get the float data from the EEPROM at position 'eeAddress' EEPROM.get(eeAddress, f); //这里一次读取了一个float大小的数据 Serial.println(f, 3); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float. /*** As get also returns a reference to 'f', you can use it inline. E.g: Serial.print( EEPROM.get( eeAddress, f ) ); ***/ /*** Get can be used with custom structures too. I have separated this into an extra function. ***/ secondTest(); //Run the next test. } struct MyObject { float field1; byte field2; char name[10]; }; void secondTest() { int eeAddress = sizeof(float); //Move address to the next byte after float 'f'. MyObject customVar; //Variable to store custom object read from EEPROM. EEPROM.get(eeAddress, customVar); //这里一次读取了MyObject这个结构体这么大的数据 Serial.println("Read custom object from EEPROM: "); Serial.println(customVar.field1); Serial.println(customVar.field2); Serial.println(customVar.name); } void loop() { /* Empty loop */ }

我们可以看看get函数的实现:使用了模板类来实现

template T &get( int idx, T &t ){ EEPtr e = idx; uint8_t *ptr = (uint8_t*) &t; for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e; return t; }

另外在这个模板类中有一个EEPtr 结构体:

struct EEPtr{ //一下全是对这个操作符重载函数 EEPtr( const int index ) : index( index ) {} operator int() const { return index; }//当要返回int类型值时调用这个 EEPtr &operator=( int in ) { return index = in, *this; } //Iterator functionality. bool operator!=( const EEPtr &ptr ) { return index != ptr.index; } EERef operator*() { return index; } /** Prefix & Postfix increment/decrement **/ EEPtr& operator++() { return ++index, *this; } EEPtr& operator--() { return --index, *this; } EEPtr operator++ (int) { return index++; } EEPtr operator-- (int) { return index--; } int index; //Index of current EEPROM cell. };

这里面有一个EERef 很重要:EERef 里有一个=符号重载:eeprom_write_byte( (uint8_t*) index, in )。这个是关键。

struct EERef{ EERef( const int index ) : index( index ) {} //Access/read members. uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); } operator uint8_t() const { return **this; } //Assignment/write members. EERef &operator=( const EERef &ref ) { return *this = *ref; } EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; } EERef &operator +=( uint8_t in ) { return *this = **this + in; } EERef &operator -=( uint8_t in ) { return *this = **this - in; } EERef &operator *=( uint8_t in ) { return *this = **this * in; } EERef &operator /=( uint8_t in ) { return *this = **this / in; } EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; } EERef &operator %=( uint8_t in ) { return *this = **this % in; } EERef &operator &=( uint8_t in ) { return *this = **this & in; } EERef &operator |=( uint8_t in ) { return *this = **this | in; } EERef &operator in; } EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; } /** Prefix increment/decrement **/ EERef& operator++() { return *this += 1; } EERef& operator--() { return *this -= 1; } /** Postfix increment/decrement **/ uint8_t operator++ (int){ uint8_t ret = **this; return ++(*this), ret; } uint8_t operator-- (int){ uint8_t ret = **this; return --(*this), ret; } int index; //Index of current EEPROM cell. };

我们可以看到这个get方法的实现还是比较绕的,最后总结下这个get方法的调用过程。

首先调用:EEPROM.get(eeAddress, customVar);然后进入到:for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;get方法就是在这里实现多字节读取的。

根据传入的参数类型大小逐字节读取数据:*ptr++ = *e。你以为这只是一句简单的加减赋值?但它才是读数据的关键一步。 *ptr++ = *e这一句是怎么把数据读出来的呢?这就用到了前面的操作符重载了。

首先*e对应EEPtr里面的*运算符重载EERef operator*() { return index; }再是 *e实际就是EERef,对应的是先调用EERef里面的构造函数EERef( const int index ) : index( index )又因为*ptr是uint8_t,其*ptr=EERef会调用operator uint8_t() const { return **this; }而**this实际是*(*this),也就是会调用EERef的*运算符uint8_t operator*() const { return eeprom_read_byte((uint8_t*) index ); }。最后去调用eeprom_read_byte((uint8_t*) index )实现读取。

另外*ptr++;实际是*ptr;ptr+=1;

二、put和write的区别

其实了解了get的原理,对应的put和write也是一样的了

①write:单字节写入

write就是单字节写入:除了通过write外还有另一种方法写入:EEPROM[index] = 1;其实现原来跟write一样。贴个管方用例:

#include /** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ int addr = 0; void setup() { /** Empty setup. **/ } void loop() { /*** Need to divide by 4 because analog inputs range from 0 to 1023 and each byte of the EEPROM can only hold a value from 0 to 255. ***/ int val = analogRead(0) / 4; /*** Write the value to the appropriate byte of the EEPROM. these values will remain there when the board is turned off. ***/ EEPROM.write(addr, val); addr = addr + 1; if (addr == EEPROM.length()) { addr = 0; } /*** As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an EEPROM address is also doable by a bitwise and of the length - 1. ++addr &= EEPROM.length() - 1; ***/ delay(100); }

其实write方法就是

void write( int idx, uint8_t val ) {(EERef( idx )) = val; } ②put:多个字节的写入

put方法与get方法及其类似,也是实现多个字节的写入:实现的基本原理大致相同,有细微区别,不在赘述。

template const T &put( int idx, const T &t ){ EEPtr e = idx; const uint8_t *ptr = (const uint8_t*) &t; for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ ); return t; } 三、clear,crc,iteration,update的用法 ①clear:擦除所有

实际上就是把每个地址写0

/* * EEPROM Clear * * Sets all of the bytes of the EEPROM to 0. * Please see eeprom_iteration for a more in depth * look at how to traverse the EEPROM. * * This example code is in the public domain. */ #include void setup() { // initialize the LED pin as an output. pinMode(13, OUTPUT); /*** Iterate through each byte of the EEPROM storage. Larger AVR processors have larger EEPROM sizes, E.g: - Arduno Duemilanove: 512b EEPROM storage. - Arduino Uno: 1kb EEPROM storage. - Arduino Mega: 4kb EEPROM storage. Rather than hard-coding the length, you should use the pre-provided length function. This will make your code portable to all AVR processors. ***/ for (int i = 0 ; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3